package test;

import java.io.File;
import java.nio.FloatBuffer;
import java.util.LinkedList;

import org.checkboo.hopefullyengine.boundingvolumes.AxisAlignedBoundingBox;
import org.checkboo.hopefullyengine.collision.Ray;
import org.checkboo.hopefullyengine.inversekinematics.AnimationController;
import org.checkboo.hopefullyengine.light.DirectionalLight;
import org.checkboo.hopefullyengine.light.PointLight;
import org.checkboo.hopefullyengine.light.SpotLight;
import org.checkboo.hopefullyengine.loaders.LoaderObj;
import org.checkboo.hopefullyengine.loaders.LoaderOgre;
import org.checkboo.hopefullyengine.sceneelements.BaseObject;
import org.checkboo.hopefullyengine.sceneelements.Color;
import org.checkboo.hopefullyengine.sceneelements.Renderer;
import org.checkboo.hopefullyengine.sceneelements.Texture;
import org.checkboo.hopefullyengine.sceneelements.Texture.MagFilter;
import org.checkboo.hopefullyengine.sceneelements.Texture.MinFilter;
import org.checkboo.hopefullyengine.sceneelements.Texture.Wrap;
import org.checkboo.hopefullyengine.scenegraph.GeometryNode;
import org.checkboo.hopefullyengine.scenegraph.GroupNode;
import org.checkboo.hopefullyengine.scenegraph.LightNode;
import org.checkboo.hopefullyengine.text.Font;
import org.checkboo.hopefullyengine.text.Text;
import org.checkboo.hopefullyengine.text.TextManager;
import org.checkboo.math.Matrix33f;
import org.checkboo.math.Quaternion;
import org.checkboo.math.Vector2f;
import org.checkboo.math.Vector3f;
import org.lwjgl.BufferUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;

public class Main {
	private boolean done = false;

	private Renderer renderer;
	private BaseObject model,vase;
	private SpotLight spot;
	private DirectionalLight dir;
	private float angle = 0.0f,angle2 = 0.0f;
	private Quaternion rot;
	private Quaternion rot2;
	private long oldTime;
	private boolean rotate;
	private boolean pressedR;
	private GroupNode rootNode,modelsNode,lights,rotation;
	private GeometryNode modelNode,modelNode2,modelNode3,modelNode4,modelNode5,modelNode6,vaseNode;
	private LightNode dirLightNode,SpotLightNode;
	private AnimationController idle;
	private Ray pointer;
	private Texture turtle, marble;
	private Text text, collision, fps, averageFPS;
	private long average = 0;
	private Vector3f oldVector;
	private float yaw,pitch,roll;
	
	private LinkedList<GeometryNode> vases;
	
	private boolean print = true;

	public static void main(String[] args){
		Main l5 = new Main();
		l5.run();
	}

	public void run() {
		try {
			init();
			renderer.init();
			while (!done) {
				update();
				renderer.render();
			}
			renderer.cleanup();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}
	
	
	private void init(){
		rootNode = new GroupNode("root");
		rotation = new GroupNode("rotation");
		rootNode.addChild(rotation);
		
		
		File f = new File("/home/checkboo/Cube.mesh.xml");
		
		model = LoaderOgre.loadFile(f);
		model.calculateVertexNormals();
		
		//this.done = true;
		idle = new AnimationController(model, "bend");
		idle.startAnimation(System.currentTimeMillis());
		
		
		/*System.out.println(aabb.getV1().toString());
		System.out.println(aabb.getV2().toString());
		System.out.println(aabb.getV3().toString());
		System.out.println(aabb.getV4().toString());
		System.out.println(aabb.getV5().toString());
		System.out.println(aabb.getV6().toString());
		System.out.println(aabb.getV7().toString());
		System.out.println(aabb.getV8().toString());
		*/
		Quaternion flip = new Quaternion();
		flip.fromAngleAxis(180.0f, new Vector3f(0.0f, 1.0f, 0.0f));
		
		modelNode = new GeometryNode("model1", model, flip, new Vector3f(0.0f, -4.0f, -15.0f), new Vector3f(0.45f, 0.45f, 0.45f));
		modelNode.setBoundingVolume(new AxisAlignedBoundingBox());
		modelNode2 = new GeometryNode("model2", model, flip, new Vector3f(-6.0f, -4.0f, -15.0f), new Vector3f(0.4f, 0.4f, 0.4f));
		modelNode2.setBoundingVolume(new AxisAlignedBoundingBox());
		modelNode3 = new GeometryNode("model3", model, flip, new Vector3f(6.0f, -4.0f, -15.0f), new Vector3f(0.4f, 0.4f, 0.4f));
		modelNode3.setBoundingVolume(new AxisAlignedBoundingBox());
		modelNode4 = new GeometryNode("model4", model, flip, new Vector3f(0.0f, -4.0f, -20.0f), new Vector3f(0.4f, 0.4f, 0.4f));
		modelNode4.setBoundingVolume(new AxisAlignedBoundingBox());
		modelNode5 = new GeometryNode("model5", model, flip, new Vector3f(-6.0f, -4.0f, -20.0f), new Vector3f(0.4f, 0.4f, 0.4f));
		modelNode5.setBoundingVolume(new AxisAlignedBoundingBox());
		modelNode6 = new GeometryNode("model6", model, flip, new Vector3f(6.0f, -4.0f, -20.0f), new Vector3f(0.4f, 0.4f, 0.4f));
		modelNode6.setBoundingVolume(new AxisAlignedBoundingBox());
		
		/*File f2 = new File("/home/checkboo/cube.obj");
		vase = LoaderObj.loadFile(f2);
		vases = new LinkedList<GeometryNode>();
		marble = new Texture("vase", "/home/checkboo/GREEN MARBLE.JPG", MinFilter.LINEAR_MIPMAP_LINEAR, MagFilter.LINEAR, Wrap.CLAMP, Wrap.CLAMP);
		vase.setTexture(marble);
		for(int i=0; i<125; i++){
			vaseNode = new GeometryNode("vase"+i, vase, new Quaternion(), new Vector3f((i%5)*4.0f-8.0f, (i/25)*4.0f-8.0f, -(int)(i/5)%5*4-10.0f), new Vector3f(1.0f, 1.0f, 1.0f));
			vaseNode.setBoundingVolume(new AxisAlignedBoundingBox());
			vases.add(vaseNode);
			rotation.addChild(vases.getLast());
		}
		*/
		
		
		this.turtle = new Texture("turtleTex", "/home/checkboo/turtle1.png", MinFilter.LINEAR_MIPMAP_LINEAR, MagFilter.LINEAR, Wrap.CLAMP, Wrap.CLAMP);
		model.setTexture(turtle);
		
			


		
		
		renderer = new Renderer();
		rotate = false;
		
		rot2 = new Quaternion();
		
		modelsNode = new GroupNode("models");
		
		//modelNode.setRotation(rot2);
		modelsNode.addChild(modelNode);
		modelsNode.addChild(modelNode2);
		modelsNode.addChild(modelNode3);
		modelsNode.addChild(modelNode4);
		modelsNode.addChild(modelNode5);
		modelsNode.addChild(modelNode6);
		
		modelsNode.setLocalTranslation(new Vector3f(0.0f, 0.0f, -10.0f));
		
		rotation.addChild(modelNode);
        
        spot = new SpotLight(new Color(1.0f, 1.0f, 1.0f, 1.0f), 
        					new Color(1.0f, 1.0f, 1.0f, 1.0f), 
        					new Color(1.0f, 1.0f, 1.0f, 1.0f), 
        					new Vector3f(0.0f, 0.0f, 0.0f), 
        					new Vector3f(0.0f, 0.0f, -1.0f), 
        					5.0f);
        
        dir  = new DirectionalLight(new Color(1.0f, 1.0f, 1.0f, 1.0f), 
								new Color(0.0f, 0.0f, 0.0f, 1.0f), 
								new Color(1.0f, 1.0f, 1.0f, 1.0f), 
								new Vector3f(1.0f, 0.0f, 0.0f));
        
        PointLight pl = new PointLight(new Color(1.0f, 1.0f, 1.0f, 1.0f), 
								new Color(0.0f, 0.0f, 0.0f, 1.0f), 
								new Color(1.0f, 1.0f, 1.0f, 1.0f), 
								new Vector3f(15.0f, 0.0f, 0.0f));
        
        dirLightNode = new LightNode("point light",pl);
        dirLightNode.setLocalTranslation(new Vector3f(0.0f, 0.0f, -15.0f));
        
        SpotLightNode = new LightNode("spotlight",spot);
        
        lights = new GroupNode("lights");
        
        //lights.addChild(SpotLightNode);
        lights.addChild(dirLightNode);
        
        rotation.addChild(lights);
		renderer.setRootNode(rootNode);
		oldTime = System.currentTimeMillis();
		
		pointer = new Ray();
		
		Texture fontTex = new Texture("default", "/home/checkboo/font2.png", MinFilter.LINEAR, MagFilter.LINEAR, Wrap.REPEAT, Wrap.REPEAT);
		Font font = new Font("font", fontTex);
        text = new Text("pick", "", font, new Color(0.0f, 1.0f, 0.0f, 1.0f), new Vector2f(20.0f, 650.0f), new Vector2f(1.0f, 1.0f));
        collision = new Text("collision", "not colliding", font, new Color(1.0f, 1.0f, 0.0f, 1.0f), new Vector2f(20.0f, 600.0f), new Vector2f(1.0f, 1.0f));
        fps = new Text("FPS", "", font, new Color(0.0f, 1.0f, 1.0f, 1.0f), new Vector2f(20.0f, 550.0f), new Vector2f(1.0f, 1.0f));
        averageFPS = new Text("average FPS", "", font, new Color(0.0f, 1.0f, 1.0f, 1.0f), new Vector2f(20.0f, 500.0f), new Vector2f(1.0f, 1.0f));
        
        TextManager.getInstance().addText(text);
        TextManager.getInstance().addText(collision);
        TextManager.getInstance().addText(fps);
        TextManager.getInstance().addText(averageFPS);
	}

	private void update() {
		long delta = System.currentTimeMillis() - oldTime;
		if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) || Display.isCloseRequested()){
			done = true;
		}
		
		if(Keyboard.isKeyDown(Keyboard.KEY_RIGHT)){
			//angle = (angle+0.12f*delta)%360;
			//rot2.fromAngleAxis(angle, new Vector3f(0.0f, 1.0f, 0.0f));
			rootNode.setLocalTranslation(new Vector3f(rootNode.getLocalTranslation().getX()-0.01f*delta, rootNode.getLocalTranslation().getY(), rootNode.getLocalTranslation().getZ()));
		}
		
		if(Keyboard.isKeyDown(Keyboard.KEY_LEFT)){
			//angle = (angle-0.12f*delta)%360;
			//rot2.fromAngleAxis(angle, new Vector3f(0.0f, 1.0f, 0.0f));
			rootNode.setLocalTranslation(new Vector3f(rootNode.getLocalTranslation().getX()+0.01f*delta, rootNode.getLocalTranslation().getY(), rootNode.getLocalTranslation().getZ()));
		}
		
		if(Keyboard.isKeyDown(Keyboard.KEY_UP)/* && !Collision.areColliding(modelNode, vaseNode)*/){
			//angle = angle <= 0.0f ? 360.0f : angle-0.12f*delta;
			//rot2.fromAngleAxis(angle, new Vector3f(1.0f, 0.0f, 0.0f));
			rootNode.setLocalTranslation(new Vector3f(rootNode.getLocalTranslation().getX(), rootNode.getLocalTranslation().getY(), rootNode.getLocalTranslation().getZ()+0.01f*delta));
		}
		
		if(Keyboard.isKeyDown(Keyboard.KEY_DOWN)){
			//angle = angle >= 360.0f ? 0 : angle+0.12f*delta;
			//rot2.fromAngleAxis(angle, new Vector3f(1.0f, 0.0f, 0.0f));
			rootNode.setLocalTranslation(new Vector3f(rootNode.getLocalTranslation().getX(), rootNode.getLocalTranslation().getY(), rootNode.getLocalTranslation().getZ()-0.01f*delta));
		}		
		
		if(Keyboard.isKeyDown(Keyboard.KEY_A) && !pressedR){
			pressedR = true;
			if(idle.isStarted())
				idle.stopAnimation();
			else
				idle.startAnimation(System.currentTimeMillis());
		}
		if(!Keyboard.isKeyDown(Keyboard.KEY_A)){
			pressedR = false;
		}
		
		/*if(Collision.areColliding(modelNode, vaseNode)){
			collision.setText("colliding");
		}
		else
			collision.setText("not colliding");*/
		
		
		FloatBuffer position = Renderer.getMousePosition(Mouse.getX(), Mouse.getY());
		//System.out.println(position.get()+" , "+position.get()+" , "+position.get());
		Vector3f second = new Vector3f(position.get(), -position.get(), position.get());
		FloatBuffer eye = BufferUtils.createFloatBuffer(16);
		GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, eye);
		Vector3f origin = new Vector3f(eye.get(3), eye.get(7), eye.get(11));
		pointer.fromPoints(origin, second);
		//System.out.println("origin: "+origin.toString()+"\nsecond: "+second.toString());
		if(null == oldVector){
			oldVector = second;
		}
		
		if(Mouse.isButtonDown(0)){
			yaw -= Mouse.getDX()*0.01;//FloatMath.atan2(second.getX(), second.getZ()) - FloatMath.atan2(oldVector.getX(), oldVector.getZ());
			pitch -= Mouse.getDY()*0.01;//FloatMath.atan2(second.getY(), second.getZ()) - FloatMath.atan2(oldVector.getY(), oldVector.getZ());
			//roll += FloatMath.atan2(second.getX(), second.getY()) - FloatMath.atan2(oldVector.getX(), oldVector.getY());
			
			rot2.fromRotationMatrix((new Matrix33f()).fromAngles(yaw, pitch, 0.0f));
		}
		oldVector = second;
		
		/*if(Collision.areColliding(pointer, vaseNode, 0.0f, 40.0f))
			text.setText("gottcha");
		else
			text.setText(":(");*/
		idle.updateAnimation(System.currentTimeMillis());
		//idle.stopAnimation();
		rotation.setLocalRotation(rot2);
		//lights.setRotation(rot2);
		if(delta != 0){
			fps.setText("object count: "+renderer.getNumObjects()+"  vertex count: "+renderer.getNumVertices()+"   FPS: "+(1000/delta));
		}
		oldTime = System.currentTimeMillis();
	}

}